import { rxccconfig } from './RxCCConfig';
import { Observable, EMPTY, Subscription, filter } from 'rxjs';
import { Button, isValid, warn, Node, KeyCode } from "cc";
import { KeyUp } from './KeyEvent';


export function BindButtonEx(button: Button, hotKeyCode?: KeyCode): Observable<Button> {
    if (!button) { warn('BindButton, button is null'); return EMPTY; }
    return new Observable(observer => {
        const clickCallback = param => {
            rxccconfig.buttonWillClickCommand.execute({ node: button.node });
            observer.next(param);
        }
        button.node.on(Button.EventType.CLICK, clickCallback);

        const touchStartCallback = _ => {
            rxccconfig.buttonTouchStartCommand.execute({ node: button.node });
        };
        const touchEndCallback = _ => {
            rxccconfig.buttonTouchEndCommand.execute({ node: button.node });
        };
        button.node.on(Node.EventType.TOUCH_START, touchStartCallback)
        button.node.on(Node.EventType.TOUCH_END, touchEndCallback)

        return () => {
            if (isValid(button.node)) {
                button.node.off(Button.EventType.CLICK, clickCallback);
                button.node.off(Node.EventType.TOUCH_START, touchStartCallback);
                button.node.off(Node.EventType.TOUCH_END, touchEndCallback);
            }
        }
    })
}

export function BindButton(button: Button, hotKeyCode?: KeyCode): Observable<Button> {
    if (!button) { warn('BindButton, button is null'); return EMPTY; }
    return new Observable(observer => {
        const clickCallback = param => {
            rxccconfig.buttonWillClickCommand.execute({ node: button.node });
            observer.next(param);
        }
        button.node.on(Button.EventType.CLICK, clickCallback);
        return () => {
            if (isValid(button.node)) {
                button.node.off(Button.EventType.CLICK, clickCallback);
            }
        }
    })
}

declare module "cc" {
    interface Button {
        subscribe: (callback: (param: any) => void, target: any, hotKeyCode?: KeyCode) => Subscription;
    }
}

Button.prototype.subscribe = function (callback: (param: any) => void, target, hotKeyCode?: KeyCode): Subscription {
    let subscription = BindButton(this as Button).subscribe(callback.bind(target));
    hotKeyCode != null && subscription.add(KeyUp().pipe(filter(_ => _ == hotKeyCode)).subscribe(_ => {
        if (!this.interactable) return;
        rxccconfig.buttonWillClickCommand.execute({ node: this.node });
        callback.call(target);
    }));
    return subscription;
};